﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web;

namespace Super.Common
{
    public class KeyValue<TKey, TValue>
    {
        public KeyValue(TKey key, TValue value)
        {
            Key = key;
            Value = value;
        }

        public TKey Key { get; set; }

        public TValue Value { get; set; }
    }


    /// <summary> 基于会话的数据(更轻量级,高效,易维护)
    /// </summary>
    public class SessionData<TKey, TValue> : IDictionary<TKey, TValue>
    {
        #region 私有成员

        /// <summary> 基于会话的Diction 包含了此种类型的所有记录.
        /// </summary>
        public static Dictionary<string, KeyValue<DateTime, Dictionary<TKey, TValue>>> StaticSessionDataList = new Dictionary<string, KeyValue<DateTime, Dictionary<TKey, TValue>>>();

        private TimeSpan _timeOutSpan;

        /// <summary> 保存的数据 Key = Key, Value.Key = 创建时间 Value.Value = Value.
        /// </summary>
        private Dictionary<TKey, TValue> _data;

        #endregion

        private Stopwatch sw = new Stopwatch();

        /// <summary> 创建SessionData
        /// </summary>
        /// <param name="key">会话数据Key</param>
        /// <param name="timeOutSpan">会话过期时间</param>
        public SessionData(string key, TimeSpan timeOutSpan)
        {
            _timeOutSpan = timeOutSpan;

            //如果Cookie存在,则取Cookie作为Key, 否则取SessionId作为Key,并写入Cookie.
            var ck = HttpContext.Current.Request.Cookies["__SessionID"];
            if (ck == null)
            {
                ck = new HttpCookie("__SessionID") { Value = HttpContext.Current.Session.SessionID + "sick", Expires = new DateTime(2020, 12, 31) };
                HttpContext.Current.Response.SetCookie(ck);
            }

            var sk = ck.Value + "_" + key;

            //移除掉过期的数据 每分钟刷新一次.
            if (sw.Elapsed.TotalMinutes > 1)
            {
                var dt = DateTime.Now;
                var rmks = StaticSessionDataList.Where(j => j.Key != sk && (j.Value.Key < dt || j.Value.Value.Count == 0)).Select(j => j.Key).ToList();
                foreach (var rmk in rmks)
                {
                    StaticSessionDataList.Remove(rmk);
                }
            }

            //如果已有数据,则使用旧数据,否则新建数据.
            if (StaticSessionDataList.ContainsKey(sk))
            {
                _data = StaticSessionDataList[sk].Value;
                //会话状态保持
                StaticSessionDataList[sk].Key = DateTime.Now.Add(_timeOutSpan);
            }
            else
            {
                _data = new Dictionary<TKey, TValue>();
                StaticSessionDataList[sk] = new KeyValue<DateTime, Dictionary<TKey, TValue>>(DateTime.Now.Add(_timeOutSpan), _data);
            }
        }

        /// <summary> 索引元素
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public TValue this[TKey key, TValue defaultValue]
        {
            get
            {
                return _data.ContainsKey(key) ? _data[key] : defaultValue;
            }
            set
            {
                _data[key] = value;
            }
        }

        public TValue this[TKey key]
        {
            get { return _data.ContainsKey(key) ? _data[key] : default(TValue); }
            set { _data[key] = value; }
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _data.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(KeyValuePair<TKey, TValue> item)
        {
            _data.Add(item.Key, item.Value);
        }

        public void Clear()
        {
            _data.Clear();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _data.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return _data.Remove(item.Key);
        }

        public int Count
        {
            get { return _data.Count; }
        }

        public bool IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        public bool ContainsKey(TKey key)
        {
            return _data.ContainsKey(key);
        }

        public void Add(TKey key, TValue value)
        {
            _data.Add(key, value);
        }

        public bool Remove(TKey key)
        {
            return _data.Remove(key);
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            return _data.TryGetValue(key, out value);
        }


        public ICollection<TKey> Keys
        {
            get { return _data.Keys; }
        }

        public ICollection<TValue> Values
        {
            get { return _data.Values; }
        }
    }
}
